#pragma once
#include <iostream>
#include <sys/types.h>
#include <cstring>
#include <sys/socket.h>
#include <algorithm>
#include <memory>
#include "InetAddr.hpp"
#include "Log.hpp"

// 本文件使用多态实现socket的封装

// TCPSocket的实现，找到所有socket的共同点，需要基于sockfd来实现
// 因此封装sockfd，server有listen_sockfd与sockfd，client有sockfd
// 因此我们可以通过实例化不同对象来实现
// 用listen_sockfd的对象来实例化accept得到的sockfd
namespace socket_ns
{
    class Socket;
    using socket_ptr = std::shared_ptr<Socket>;
    int gback = 5;
    enum
    {
        SOCKET_ERROR = 1,
        BIND_ERROR,
        LISTEN_ERROR,
    };
    // 基类
    class Socket
    {

    public:
        virtual void CreateSocket() = 0;
        virtual void BindSocket(InetAddr &localaddr) = 0;
        virtual void ListenSocket() = 0;
        virtual socket_ptr AcceptSocket(InetAddr *addr) = 0; // 将客户端的信息输出
        virtual bool ConnectSocket(InetAddr &sever_addr) = 0;
        virtual int SockFd() = 0;
        virtual int Recv(std::string *recvmessage) = 0;
        virtual int Send(std::string &sendmessage) = 0;

    public:
        void BuildServerSocket(InetAddr &localaddr)
        {
            CreateSocket();
            BindSocket(localaddr);
            ListenSocket();
        }
        bool BuildClientSocket(InetAddr &addr)
        {
            CreateSocket();
            return ConnectSocket(addr);
        }
    };

    class TcpSocket : public Socket
    {
    public:
        TcpSocket(int sockfd = -1) : _sockfd(sockfd)
        {
        }
        // 创建sockfd
        void CreateSocket() override
        {
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                Log(FATAL, "socket fail...");
                exit(SOCKET_ERROR);
            }
            // Log(DEBUG, "socket success...");
        }

        // 绑定sockfd与套接字结构体
        // 绑定sockfd与包含本地信息的套接字结构体
        void BindSocket(InetAddr &localaddr) override
        {
            struct sockaddr_in local;
            local.sin_family = AF_INET;
            local.sin_addr.s_addr = inet_addr(localaddr.IP().c_str());
            local.sin_port = htons(localaddr.port());
            int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(localaddr));
            if (n < 0)
            {
                Log(FATAL, "bind fail...");
                exit(BIND_ERROR);
            }
            Log(DEBUG, "bind success...");
        }
        // 打开监听状态
        void ListenSocket() override
        {
            int n = listen(_sockfd, gback);
            if (n < 0)
            {
                Log(FATAL, "listen fail...");
                exit(LISTEN_ERROR);
            }
            Log(DEBUG, "listen success...");
        }
        // 接收连接请求
        // 服务器接受来自客户端的连接请求，并返回得到的sockfd，存储远端的套接字结构体
        socket_ptr AcceptSocket(InetAddr *addr) override
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int fd = accept(_sockfd, (struct sockaddr *)&peer, &len);
            // Log(INFO,"new connection create success...");
            if (fd < 0)
            {
                Log(DEBUG, "accept fail...");
                return nullptr;
            }
            *addr = peer;
            socket_ptr sock = std::make_unique<TcpSocket>(fd);
            return sock;
        }
        // 客户端向服务器发送连接请求，成功返回0，失败返回-1
        bool ConnectSocket(InetAddr &addr) override
        {
            struct sockaddr_in server;
            memset(&server, 0, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = ntohs(addr.port());
            server.sin_addr.s_addr = inet_addr(addr.IP().c_str());
            int n = connect(_sockfd, (struct sockaddr *)&server, sizeof(server));
            if (n == 0)
            {
                return true;
            }
            return false;
        }
        // 返回sockfd
        int SockFd()
        {
            return _sockfd;
        }
        // recv
        // 将收到的内容通过输出型参数返回
        int Recv(std::string *recvmessage) override
        {

            char buffer[1024];
            int n = recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
            // Log(DEBUG,"recving...");
            if (n > 0)
            {
                buffer[n] = 0;
            }
            *recvmessage += buffer; // 处理字节流的粘报问题，如果当前recvmessage内存在半个，加上后面半个才完整
            return n;
        }
        // send
        // 向客户端发送报文
        int Send(std::string &sendmessage) override
        {
            // Log(DEBUG,"sending...");
            //std::cout << "Send... Sendmessage: " << sendmessage << std::endl;
            int n = send(_sockfd, sendmessage.c_str(), sendmessage.size(), 0);
            return n;
        }

    private:
        int _sockfd;
    };

}